(function (root) {
    root.form_to_json = function (selector) {
        var parsingPathPosition = function (key) {
            var positions = []
            var matchPositions = []
            var groups = []
            var regex = /\[([^\]]*)]/g
            while ((m = regex.exec(key)) !== null) {
                if (m.index === regex.lastIndex) {
                    regex.lastIndex++;
                }
                m.forEach((match, groupIndex) => {
                    if (groupIndex === 0) {
                        groups.push({
                            start: m.index,
                            end: m.index + match.length
                        })
                    }
                });
            }
            $.each(groups, function (i, group) {
                matchPositions.push({
                    start: group.start,
                    end: group.end,
                    type: "GROUP"
                })
            });
            if (matchPositions.length === 0) {
                positions.push({
                    start: 0,
                    end: key.length,
                    type: "TEXT"
                })
            } else {
                for (let i = 0; i < matchPositions.length; i++) {
                    var currentPosition = matchPositions[i];
                    var nextPosition = (i + 1) < matchPositions.length ? matchPositions[i + 1] : null;
                    if (i === 0 && currentPosition.start > 0) {
                        positions.push({
                            start: 0,
                            end: currentPosition.start,
                            type: "TEXT"
                        })
                    }
                    positions.push({
                        start: currentPosition.start,
                        end: currentPosition.end,
                        type: "GROUP",
                    })
                    if (nextPosition != null) {
                        if (currentPosition.end !== nextPosition.start) {
                            positions.push({
                                start: currentPosition.end,
                                end: nextPosition.start,
                                type: "TEXT",
                            })
                        }
                    }
                    if (nextPosition == null && currentPosition.end < key.length) {
                        positions.push(
                            {
                                start: currentPosition.end,
                                end: key.length,
                                type: "TEXT",
                            })
                    }
                }
            }
            return positions
        }

        var trim = function (s, c) {
            var len = s.length;
            var st = 0;
            while ((st < len) && (s.charAt(st) === c)) {
                st++;
            }
            while ((st < len) && (s.charAt(len - 1) === c)) {
                len--;
            }
            return ((st > 0) || (len < s.length)) ? s.substring(st, len) : s;
        }

        var parsingPathV2 = function (key) {
            var paths = []
            var positions = parsingPathPosition(key)
            for (let i = 0; i < positions.length; i++) {
                var position = positions[i]
                switch (position.type) {
                    case "GROUP":
                        var group = key.substring(position.start + 1, position.end - 1).trim();
                        paths.push("" === group ? "0" : group);
                        break;
                    case "TEXT":
                        var text = trim(key.substring(position.start, position.end).trim(), '.'); // 出去开头的.
                        var subPaths = text.split(".");
                        for (let j = 0; j < subPaths.length; j++) {
                            var subPath = subPaths[j]
                            paths.push("" === subPath ? "0" : subPath);
                        }
                        break;
                }
            }
            return paths
        }

        var toNested = function (kv) {
            var r = {}
            $.each(kv, function (k, v) {
                var paths = parsingPathV2(k);
                var c = r;
                for (let i = 0; i < paths.length; i++) {
                    var path = paths[i];
                    if (i === paths.length - 1) {
                        c[path] = v
                    } else {
                        var s = c[path]
                        if (s == null) {
                            s = {}
                            c[path] = s
                        }
                        c = s
                    }
                }
            });
            return r
        }
        var kv = {};
        var arr = $(selector).serializeArray();
        $.each(arr, function (i, item) {
            if (kv[item['name']]) {
                var old = kv[item['name']];
                if (!_.isArray(old)) {
                    kv[item['name']] = [];
                    kv[item['name']].push(old);
                }
                kv[item['name']].push(item['value']);
            } else {
                kv[item['name']] = item['value'];
            }
        });
        return toNested(kv);
    }
})(window);